#I HATE THIS PROGRAM!!! 
#imports
from Tkinter import *
import struct
from array import array
from math import sin, pi
from random import random
import wave, winsound, sys, codecs


#declaration
SR = 44100
NCHANNELS = 1
SWIDTH = 2
FRAME_RATE = 44100
NFRAMES = 44100
NSAMPLES = 44100
MAX_VAL = 32767
WAVE_FORMAT_PCM = 0x001
samples = []


#Freq's
FreqArray = [
#     C       C#       D        D#        E        F       F#        G       G#        A        B        H  octave
  65.41,   69.30,   73.91,   77.78,   82.41,   87.31,   92.50,   98.00,  103.80,  110.00,  116.54,  123.48, #major
 130.82,  138.59,  147.83,  155.56,  164.81,  174.62,  185.00,  196.00,  207.00,  220.00,  233.08,  246.96, #minor
 261.63,  277.18,  293.66,  311.13,  329.63,  349.23,  369.99,  392.00,  415.30,  440.00,  466.16,  493.88, #first
 523.25,  554.36,  587.32,  622.26,  659.26,  698.46,  739.98,  784.00,  830.60,  880.00,  932.32,  987.75, #second
1046.50, 1108.70, 1174.60, 1244.50, 1318.50, 1396.90, 1480.00, 1568.00, 1661.20, 1720.00, 1864.60, 1975.50, #third
2093.00, 2217.40, 2349.20, 2489.00, 2637.00, 2793.80, 2960.00, 3136.00, 3332.40, 3440.00, 3729.20, 3951.00  #fourth
]


#buttons binding
Symbols = "1234567890-=qwertyuiop[]asdfghjkl;'zxcvbnm,./"
cti = {}
numb = 0
for ch in Symbols:
    cti[ch] = numb
    numb += 1


#magic function
def info_gen(length):
    DataLength = int(length) * NCHANNELS * SWIDTH
    return str(struct.pack('<4sl4s4slhhllhh4sl',
    'RIFF', 36 + DataLength, 'WAVE', 'fmt ', 16, WAVE_FORMAT_PCM,
    NCHANNELS, FRAME_RATE, NCHANNELS * FRAME_RATE * SWIDTH,
    NCHANNELS * SWIDTH, SWIDTH * 8, 'data', DataLength))


#guitar_string_special_class
class String:
    def __init__(self, fr, SR, k):
        self.freq = fr
        self.N = SR / fr
        self.koef = k
    def pluck(self):
        self.buf = [random() - 0.5 for i in range(int(self.N))]
    def sample(self):
        val = self.buf[0]
        avg = self.koef * 0.5 * (self.buf[0] + self.buf[1])
        self.buf.append(avg)
        self.buf.pop(0)
        return val


#function plays
def play(event):
    if (cti.has_key(event.char)):
        print "try to play"
        global samples
        c = choice.get()
        if c == 1:
            koef = 0.85
            k = 0.5
        else:
            koef = 0.999
            k = 2
        cur_freq = FreqArray[cti[event.char]]
        cur_str = String(cur_freq, SR, koef)
        help_str = String(cur_freq - cur_freq * 0.01, SR, koef)
        cur_str.pluck()
        help_str.pluck()
        sample = 0.0
        for i in range(int(NSAMPLES * k)):
            sample = cur_str.sample()
            if c == 2:
                if i > NSAMPLES / 64:
                    sample += help_str.sample()
            samples.append(sample)
        tmpBuf = [int(x * MAX_VAL) for x in samples]
        data = info_gen(len(samples))
        data += array('h', tmpBuf).tostring()
        winsound.PlaySound(data, winsound.SND_MEMORY)
        tmpBuf = []
        data = ""
        samples = []


#GUI variables
buttons = []
root = Tk()
choice = IntVar()
choice.set(0)
choice2 = IntVar()
choice2.set(0)
rad0 = Radiobutton(root, text = "Normal", variable = choice, value = 0)
rad1 = Radiobutton(root, text = "Palm-Mute", variable = choice, value = 1)
rad2 = Radiobutton(root, text = "Chorus", variable = choice, value = 2)
rad3 = Radiobutton(root, text = "For Nothing", variable = choice2, value = 0)
rad4 = Radiobutton(root, text = "With Everything", variable = choice2, value = 1)
rad5 = Radiobutton(root, text = "Lobodomy", variable = choice2, value = 2)
exit_button = Button(root, text = "Quit")
for i in xrange(len(Symbols)):
    buttons.append(Button(root))
    buttons[i]["text"] = str(i)
    buttons[i]["activebackground"] = "purple"
    buttons[i].bind_all("<Key>", play)
def q(event):
    root.destroy()

exit_button.bind("<Button-1>", q)
rad0.pack()
rad1.pack()
rad2.pack()
rad3.pack()
rad4.pack()
rad5.pack()
exit_button.pack()
root.mainloop()
        






